package se.webbzon.oschi01.worldcamera;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;

import se.webbzon.oschi01.font.HorizontalAlignment;
import se.webbzon.oschi01.font.VerticalAlignment;
import se.webbzon.oschi01.friendly.Friendly;
import se.webbzon.oschi01.textureset.Texture3D;

public class WorldCameraLayer implements WorldCameraDrawable {
	
	// The buffered image used to store the world camera pane
	private final BufferedImage image;
	
	// The 2D graphics object associated with the world camera pane
	private final Graphics2D g2d;
	
	// The original and current AffineTransform in use
	private AffineTransform originalTransform;
	private final AffineTransform currentTransform;
	
	// The transparency value 
	private float transparency;
		
	// The alignment of the text
	private HorizontalAlignment hAlign;
	private VerticalAlignment vAlign;
	
	/*============================================================
	Constructors
	============================================================*/
	
	public WorldCameraLayer(Dimension d) {
		image = new BufferedImage(d.width,d.height,BufferedImage.TYPE_4BYTE_ABGR);
		g2d = image.createGraphics();
		currentTransform = new AffineTransform();
		transparency = 1;
		hAlign = HorizontalAlignment.LEFT;
		vAlign = VerticalAlignment.BOTTOM;
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Copies the dimension of the world camera layer to the given 
	 * Dimension instance. **/
	public void getDimension(Dimension d) {
		d.setSize(image.getWidth(), image.getHeight());
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Draws another layer onto this layer. **/
	public void drawLayer(int x, int y, WorldCameraLayer layer) {
		drawImage(layer.image,x,y);
	}

	@Override public void clear() {
		g2d.setComposite(AlphaComposite.Clear); 
		g2d.fillRect(0, 0, image.getWidth(), image.getHeight()); 
		g2d.setComposite(AlphaComposite.SrcOver);
	}
	
	@Override public void paint(int x, int y, Graphics g, ImageObserver observer) {
		g.drawImage(image, x, y, observer);
	}
	
	@Override public void resetTransform() {
		if (originalTransform != null)
			g2d.setTransform(originalTransform);
	}

	@Override public void setTransform(AffineTransform transform) {
		if (originalTransform == null)
			originalTransform = g2d.getTransform();
		
		currentTransform.setTransform(transform);
		transform.preConcatenate(originalTransform);
		g2d.setTransform(transform);
		transform.setTransform(currentTransform);
	}
	
	@Override public void getTransform(AffineTransform transform) {
		transform.setTransform(currentTransform);
	}
	
	@Override public void setColor(Color c) {
		g2d.setColor(c);
	}
	
	@Override public Color getColor() {
		return g2d.getColor();
	}
	
	@Override public void setBackgroundColor(Color c) {
		g2d.setBackground(c);
	}
	
	@Override public Color getBackgroundColor() {
		return g2d.getBackground();
	}
	
	@Override public void setFont(Font f) {
		g2d.setFont(f);
	}
	
	@Override public Font getFont() {
		return g2d.getFont();
	}
	
	@Override public void setTransparency(float transparency) {
		//if (transparency != this.transparency) {
			g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
														transparency));
			this.transparency = transparency;
		//}
	}
	
	@Override public float getTransparency() {
		return transparency;
	}
	
	@Override public void drawRect(int x, int y, int width, int height) {
		g2d.drawRect(x, y, width, height);
	}
	
	@Override public void fillRect(int x, int y, int width, int height) {
		g2d.fillRect(x, y, width, height);
	}
	
	@Override public void drawOval(int x, int y, int width, int height) {
		g2d.drawOval(x, y, width, height);
	}
	
	@Override public void fillOval(int x, int y, int width, int height) {
		g2d.fillOval(x, y, width, height);
	}
	
	@Override public void drawLine(int x1, int y1, int x2, int y2) {
		g2d.drawLine(x1, y1, x2, y2);
	}

	@Override public void drawImage(Image image, int x, int y) {
		g2d.drawImage(image, x, y, null);
	}

	@Override public void drawImage(Image image, int x, int y, int width, int height) {
		g2d.drawImage(image, x, y, width, height, null);
	}
	
	@Override public void drawTexture(Texture3D texture, int x, int y) {
		g2d.drawImage(texture.getImage(), x, y, null);
	}
	
	@Override public void drawTexture(Texture3D texture, int x, int y, int width, int height) {
		g2d.drawImage(texture.getImage(), x, y, width, height, null);
	}
	
	@Override public void drawString(String str, int x, int y) {
		if (hAlign != HorizontalAlignment.LEFT || vAlign != VerticalAlignment.BOTTOM) {
			Rectangle2D rect = g2d.getFontMetrics().getStringBounds(str, g2d);
			if (hAlign == HorizontalAlignment.RIGHT)
				x -= (int) rect.getMaxX();
			else if (hAlign == HorizontalAlignment.CENTER)
				x -= (int) rect.getCenterX();
			if (vAlign == VerticalAlignment.TOP)
				y -= (int) rect.getMinY();
			else
				y -= (int) rect.getCenterY();
		}
		g2d.drawString(str, x, y);
	}
	
	@Override public void setHAlignment(HorizontalAlignment alignment) {
		this.hAlign = alignment;
	}
	
	@Override public void setVAlignment(VerticalAlignment alignment) {
		this.vAlign = alignment;
	}
	
	@Override public HorizontalAlignment getHAlignment() {
		return hAlign;
	}
	
	@Override public VerticalAlignment getVAlignment() {
		return vAlign;
	}

	@Override public void clip(int x, int y, int width, int height) {
		g2d.clip(new Rectangle(x,y,width,height));
	}
	
	/*============================================================
	Friendly Methods
	============================================================*/
	
	/** Returns the buffered image of this layer. **/
	@Friendly BufferedImage getBufferedImage() {
		return image;
	}

}
